package com.sergio.compress.service;

import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.sergio.compress.dao.model.SeTestRecord;
import com.sergio.compress.dao.service.SeTestRecordService;
import com.sergio.compress.model.base.MockDataBase;
import com.sergio.compress.model.base.MockDataChildBase;
import com.sergio.compress.model.base.MockDataWrapper;
import com.sergio.compress.model.proto.Mock;
import com.sergio.compress.model.type2.*;
import com.sergio.compress.model.type3.*;
import com.sergio.compress.utils.CommonUtil;
import com.sergio.compress.utils.TransUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import static com.sergio.compress.utils.CommonUtil.generateRandomString;

/**
 * @Author : Sergio.D
 * @Description :
 * @CreateDate ：2023/6/15 19:00
 */
@Service
public class SeTest3Service {


    @Autowired
    SeTestRecordService seTestRecordService;

    private static boolean needSave = false;
    private static final Random random = new Random();

    public static long batchNum = 1;

    public void makeTest(List<MockDataBase> dataSource, int lengthSourceSe) {
        MockDataWrapper sendData = new MockDataWrapper(dataSource);
        saveSeTestResult(new Proto3().doTest(TransUtil.convertToProto(sendData), lengthSourceSe), needSave);
        saveSeTestResult(new CBOR3().doTest(sendData, lengthSourceSe), needSave);
//        saveSeTestResult(new Avro3().doTest(sendData, lengthSourceSe), needSave);
        saveSeTestResult(new ION3().doTest(sendData, lengthSourceSe), needSave);
        saveSeTestResult(new JSON3().doTest(sendData, lengthSourceSe), needSave);
//        saveSeTestResult(new Hessian3().doTest(sendData, lengthSourceSe), needSave);
        saveSeTestResult(new MsgPack3().doTest(sendData, lengthSourceSe), needSave);
        saveSeTestResult(new BSON3().doTest(sendData, lengthSourceSe), needSave);
        //跳过第一次  防止冷启动之类的出现较大的数据 拉高图表
        this.needSave = true;
    }


    public List<MockDataBase> makeData(int num) {
        List<MockDataBase> result = new LinkedList<>();
        int i = 0;
        while (i < num) {
            result.add(makeData());
            i++;
        }
        return result;
    }

    public MockDataBase makeData() {
        MockDataBase mockData = new MockDataBase();
        mockData.setStr8(generateRandomString(8));
        mockData.setStr16(generateRandomString(16));
        mockData.setStr32(generateRandomString(32));
        mockData.setStr64(generateRandomString(64));
        mockData.setStr256(generateRandomString(256));
        mockData.setGoodsId(random.nextInt(100));
        mockData.setPresentAt(Instant.now());
        mockData.setAa(CommonUtil.generateRandomBytes(10));
        mockData.setBb(random.nextFloat());
        mockData.setCc(random.nextDouble());
        mockData.setEe(random.nextLong());

        MockDataChildBase childBase = new MockDataChildBase();
        childBase.setUserId(random.nextInt(100));
        childBase.setUserName(random.nextLong());
        childBase.setUserId1(random.nextInt(100));
        childBase.setUserName1(random.nextLong());
        childBase.setUserId2(random.nextInt(100));
        childBase.setUserName2(random.nextLong());
        childBase.setAa((short) random.nextInt(100));
        childBase.setBb((byte) random.nextInt(100));
        childBase.setAa1((short) random.nextInt(100));
        childBase.setBb2((byte) random.nextInt(100));

        mockData.setChildBase(childBase);

        return mockData;
    }


    /**
     * @param minInfoLength  起始的用户个数
     * @param maxByteLength  最大字节长度   以protobuf为基准 当他序列化超过改长度后则终止
     * @param stepInfoLength 每次增加的用户个数
     */
    public void makeTest(int minInfoLength, int maxByteLength, int stepInfoLength) {
        List<MockDataBase> testSource = makeData(minInfoLength);
        int lengthSourceSe = 0;
        do {
            List<MockDataBase> add = makeData(stepInfoLength);
            testSource.addAll(add);
            try {
                JsonMapper mapper = new JsonMapper();
                mapper.registerModule(new JavaTimeModule());
                byte[] cborData = mapper.writeValueAsBytes(testSource);
                lengthSourceSe = cborData.length;
                makeTest(testSource, lengthSourceSe);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } while (lengthSourceSe < maxByteLength);
    }

    public void addBatchNum() {
        batchNum++;
    }


    public void saveSeTestResult(List<SeTestRecord> seTestRecord, boolean needSave) {
        if (needSave) {
            for (SeTestRecord seTestRecord1 : seTestRecord) {
                saveSeTestResult(seTestRecord1);
            }

        }

    }

    public void saveSeTestResult(SeTestRecord seTestRecord) {
        seTestRecord.setBatchNum(batchNum);
        seTestRecordService.save(seTestRecord);
    }

}
